package context

import (
	"context"
	"fmt"
	"time"
)

// DemoContextTimeout 演示context的超时控制
func DemoContextTimeout() {
	fmt.Println("=== Context包演示 ===")
	fmt.Println("\n--- 超时控制 ---")

	// 创建一个带有500毫秒超时的context
	ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel() // 确保资源被释放

	// 模拟一个耗时操作
	done := make(chan struct{})
	go func() {
		// 模拟耗时300毫秒的操作
		time.Sleep(300 * time.Millisecond)
		close(done)
	}()

	// 等待操作完成或超时
	select {
	case <-done:
		fmt.Println("操作成功完成")
	case <-ctx.Done():
		fmt.Printf("操作超时: %v\n", ctx.Err())
	}

	// 测试超时情况
	ctx2, cancel2 := context.WithTimeout(context.Background(), 500*time.Millisecond)
	defer cancel2()

	done2 := make(chan struct{})
	go func() {
		// 模拟耗时800毫秒的操作
		time.Sleep(800 * time.Millisecond)
		close(done2)
	}()

	select {
	case <-done2:
		fmt.Println("操作成功完成")
	case <-ctx2.Done():
		fmt.Printf("操作超时: %v\n", ctx2.Err())
	}
}

// DemoContextCancel 演示context的取消操作
func DemoContextCancel() {
	fmt.Println("\n--- 取消操作 ---")

	// 创建一个可取消的context
	ctx, cancel := context.WithCancel(context.Background())

	// 启动一个goroutine
	go func() {
		for {
			select {
			case <-ctx.Done():
				fmt.Printf("goroutine被取消: %v\n", ctx.Err())
				return
			default:
				fmt.Println("goroutine运行中...")
				time.Sleep(200 * time.Millisecond)
			}
		}
	}()

	// 运行3秒后取消
	time.Sleep(3 * time.Second)
	fmt.Println("取消goroutine...")
	cancel()

	// 等待goroutine结束
	time.Sleep(500 * time.Millisecond)
}

// DemoContextWithValue 演示context的值传递
func DemoContextWithValue() {
	fmt.Println("\n--- 值传递 ---")

	// 创建一个带有值的context
	ctx := context.WithValue(context.Background(), "userID", 123)
	ctx = context.WithValue(ctx, "userName", "张三")

	// 传递context
	processRequest(ctx)
}

func processRequest(ctx context.Context) {
	// 获取context中的值
	userID := ctx.Value("userID")
	userName := ctx.Value("userName")

	fmt.Printf("处理请求: 用户ID=%v, 用户名=%v\n", userID, userName)
}

// DemoContextFeatures 整合演示所有context特性
func DemoContextFeatures() {
	DemoContextTimeout()
	DemoContextCancel()
	DemoContextWithValue()
}
